use std::future::Future;
use std::pin::Pin;
use axum::body::Body;
use axum::debug_middleware;
use axum::http::{header, Request};
use axum::middleware::Next;
use axum::response::Response;
use serde::Deserialize;
use tower_http::auth::{AsyncAuthorizeRequest, AsyncRequireAuthorizationLayer};
use crate::config::get;

#[derive(Debug, Clone, Deserialize)]
pub struct TokenState(pub Option<String>);

#[derive(Clone)]
pub struct SatokenLayer;

impl SatokenLayer {
    pub fn new() -> AsyncRequireAuthorizationLayer<SatokenLayer> {
        AsyncRequireAuthorizationLayer::new(SatokenLayer)
    }
}

impl AsyncAuthorizeRequest<Body> for SatokenLayer {
    type RequestBody = Body;
    type ResponseBody = Body;
    type Future = Pin<Box<dyn Future<Output = Result<Request<Self::RequestBody>, Response<Self::ResponseBody>>> + Send + 'static>>;

    fn authorize(&mut self, mut request: Request<Body>) -> Self::Future {
        let prefix = get().satoken().prefix();

        Box::pin(async move {
            if let Some(token) = request.headers().get(header::AUTHORIZATION) {
                let prefix = get().satoken().prefix();
                let token_str = token.to_str().unwrap().replace(&format!("{prefix} "), "");
                request.extensions_mut().insert(TokenState(Some(token_str)));
            }

            Ok(request)
        })
    }
}